/**
  ******************************************************************************
  * @file    GPIO/IOToggle/system_stm32f10x.c
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   CMSIS Cortex-M3 Device Peripheral Access Layer System Source File.
  * 
  * 1.  This file provides two functions and one global variable to be called from 
  *     user application:
  *      - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
  *                      factors, AHB/APBx prescalers and Flash settings). 
  *                      This function is called at startup just after reset and 
  *                      before branch to main program. This call is made inside
  *                      the "startup_stm32f10x_xx.s" file.
  *
  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
  *                                  by the user application to setup the SysTick 
  *                                  timer or configure other parameters.
  *                                     
  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
  *                                 be called whenever the core clock is changed
  *                                 during program execution.
  *
  * 2. After each device reset the HSI (8 MHz) is used as system clock source.
  *    Then SystemInit() function is called, in "startup_stm32f10x_xx.s" file, to
  *    configure the system clock before to branch to main program.
  *
  * 3. If the system clock source selected by user fails to startup, the SystemInit()
  *    function will do nothing and HSI still used as system clock source. User can 
  *    add some code to deal with this issue inside the SetSysClock() function.
  *
  * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depedning on
  *    the product used), refer to "HSE_VALUE" define in "stm32f10x.h" file. 
  *    When HSE is used as system clock source, directly or through PLL, and you
  *    are using different crystal you have to adapt the HSE value to your own
  *    configuration.
  *        
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/** @addtogroup CMSIS
  * @{
  */

/** @addtogroup stm32f10x_system
  * @{
  */  
  
/** @addtogroup STM32F10x_System_Private_Includes
  * @{
  */

#include "stm32f10x.h"

/**
  * @}
  */

/** @addtogroup STM32F10x_System_Private_TypesDefinitions
  * @{
  */

/**
  * @}
  */

/** @addtogroup STM32F10x_System_Private_Defines
  * @{
  */

/*!< 取消注释下面与所需系统时钟(SYSCLK)频率对应的行
   (复位后HSI用作SYSCLK源)
   
   重要说明:
   ============== 
   1. 每次设备复位后，HSI用作系统时钟源。

   2. 请确保所选系统时钟不超过设备的最大频率。
      
   3. 如果下面没有启用任何定义，则HSI用作系统时钟源。

   4. 此文件中提供的系统时钟配置函数假设:
        - 对于低、中和高密度值线设备，使用外部8MHz晶体驱动系统时钟。
        - 对于低、中和高密度设备，使用外部8MHz晶体驱动系统时钟。
        - 对于连接线设备，使用外部25MHz晶体驱动系统时钟。
     如果您使用不同的晶体，您必须相应地调整这些函数。
    */
    
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
/* #define SYSCLK_FREQ_72MHz  72000000 */
/* 使用内部时钟64MHz */
#define SYSCLK_FREQ_64MHz  64000000
#endif

/*!< 如果您需要使用安装在STM3210E-EVAL板(STM32高密度和XL密度设备)上
     或STM32100E-EVAL板(STM32高密度值线设备)上的外部SRAM作为数据存储器，
     请取消注释以下行 */ 
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
/* #define DATA_IN_ExtSRAM */
#endif

/*!< 如果您需要将向量表重定位到内部SRAM中，请取消注释以下行 */ 
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET  0x0 /*!< 向量表基址偏移字段。
                                  此值必须是0x200的倍数。 */


/**
  * @}
  */

/** @addtogroup STM32F10x_System_Private_Macros
  * @{
  */

/**
  * @}
  */

/** @addtogroup STM32F10x_System_Private_Variables
  * @{
  */

/*******************************************************************************
*  时钟定义
*******************************************************************************/
#ifdef SYSCLK_FREQ_HSE
  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< 系统时钟频率(核心时钟) */
#elif defined SYSCLK_FREQ_24MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;        /*!< 系统时钟频率(核心时钟) */
#elif defined SYSCLK_FREQ_36MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;        /*!< 系统时钟频率(核心时钟) */
#elif defined SYSCLK_FREQ_48MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;        /*!< 系统时钟频率(核心时钟) */
#elif defined SYSCLK_FREQ_56MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;        /*!< 系统时钟频率(核心时钟) */
#elif defined SYSCLK_FREQ_72MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< 系统时钟频率(核心时钟) */
#elif defined SYSCLK_FREQ_64MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_64MHz;        /*!< 系统时钟频率(核心时钟) */
#else /*!< HSI选作系统时钟源 */
  uint32_t SystemCoreClock         = HSI_VALUE;        /*!< 系统时钟频率(核心时钟) */
#endif

__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
/**
  * @}
  */

/** @addtogroup STM32F10x_System_Private_FunctionPrototypes
  * @{
  */

static void SetSysClock(void);

#ifdef SYSCLK_FREQ_HSE
  static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
  static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
  static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
  static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
  static void SetSysClockTo56(void);  
#elif defined SYSCLK_FREQ_72MHz
  static void SetSysClockTo72(void);
#elif defined SYSCLK_FREQ_64MHz
  static void SetSysClockTo64(void);
#endif

#ifdef DATA_IN_ExtSRAM
  static void SystemInit_ExtMemCtl(void); 
#endif /* DATA_IN_ExtSRAM */

/**
  * @}
  */

/** @addtogroup STM32F10x_System_Private_Functions
  * @{
  */

/**
  * @brief  设置微控制器系统
  *         初始化嵌入式闪存接口、PLL并更新SystemCoreClock变量。
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
void SystemInit (void)
{
  /* 将RCC时钟配置重置为默认复位状态(用于调试目的) */
  /* 设置HSION位 */
  RCC->CR |= (uint32_t)0x00000001;

  /* 重置SW、HPRE、PPRE1、PPRE2、ADCPRE和MCO位 */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* 重置HSEON、CSSON和PLLON位 */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* 重置HSEBYP位 */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* 重置PLLSRC、PLLXTPRE、PLLMUL和USBPRE/OTGFSPRE位 */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* 重置PLL2ON和PLL3ON位 */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* 禁用所有中断并清除挂起位 */
  RCC->CIR = 0x00FF0000;

  /* 重置CFGR2寄存器 */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* 禁用所有中断并清除挂起位 */
  RCC->CIR = 0x009F0000;

  /* 重置CFGR2寄存器 */
  RCC->CFGR2 = 0x00000000;      
#else
  /* 禁用所有中断并清除挂起位 */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
    
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* 配置系统时钟频率、HCLK、PCLK2和PCLK1预分频器 */
  /* 配置闪存延迟周期并启用预取缓冲器 */
  SetSysClock();

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* 向量表重定位到内部SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* 向量表重定位到内部FLASH */
#endif 
}

/**
  * @brief  更新SystemCoreClock变量，根据时钟寄存器值。
  *         SystemCoreClock变量包含核心时钟(HCLK)，它可以
  *         由用户应用程序用来设置SysTick 
  *          timer或配置其他参数。
  *           
  * @note   每次核心时钟(HCLK)更改时，必须调用此函数
  *         来更新SystemCoreClock变量值。否则，任何基于此变量的配置都将不正确。         
  *     
  * @note   - 此函数计算的系统频率不是芯片中的实际频率。
  *           它是基于预定义常量和所选时钟源计算的:
  *             
  *           - 如果SYSCLK源是HSI，SystemCoreClock将包含HSI_VALUE(*)
  *                                              
  *           - 如果SYSCLK源是HSE，SystemCoreClock将包含HSE_VALUE(**)
  *                          
  *           - 如果SYSCLK源是PLL，SystemCoreClock将包含HSE_VALUE(**) 
  *             或HSI_VALUE(*)乘以PLL因子。
  *         
  *         (*) HSI_VALUE是在stm32f1xx.h文件中定义的常量(默认值
  *              8 MHz)，但实际值可能因电压和温度的变化而变化。   
  *    
  *         (**) HSE_VALUE是在stm32f1xx.h文件中定义的常量(默认值
  *               8 MHz或25 MHz，取决于所使用的产品)，用户必须确保
  *              HSE_VALUE与实际使用的晶体频率相同。
  *              否则，此函数可能产生错误结果。
  *                
  *         - 当使用HSE晶体的分数值时，此函数的结果可能不正确。
  * @param  无
  * @retval 无
  */
void SystemCoreClockUpdate (void)
{
  uint32_t tmp = 0, pllmull = 0, pllsource = 0;

#ifdef  STM32F10X_CL
  uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0;
#endif /* STM32F10X_CL */

#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  uint32_t prediv1factor = 0;
#endif /* STM32F10X_LD_VL or STM32F10X_MD_VL or STM32F10X_HD_VL */
    
  /* 获取SYSCLK源 -------------------------------------------------------*/
  tmp = RCC->CFGR & RCC_CFGR_SWS;
  
  switch (tmp)
  {
    case 0x00:  /* HSI用作系统时钟 */
      SystemCoreClock = HSI_VALUE;
      break;
    case 0x04:  /* HSE用作系统时钟 */
      SystemCoreClock = HSE_VALUE;
      break;
    case 0x08:  /* PLL用作系统时钟 */

      /* 获取PLL时钟源和乘法因子 ----------------------*/
      pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
      pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
      
#ifndef STM32F10X_CL      
      pllmull = ( pllmull >> 18) + 2;
      
      if (pllsource == 0x00)
      {
        /* HSI振荡器时钟除以2选作PLL时钟入口 */
        SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
      }
      else
      {
 #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
       prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
       /* HSE振荡器时钟选作PREDIV1时钟入口 */
       SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; 
 #else
        /* HSE选作PLL时钟入口 */
        if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET)
        {/* HSE振荡器时钟除以2 */
          SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
        }
        else
        {
          SystemCoreClock = HSE_VALUE * pllmull;
        }
 #endif
      }
#else
      pllmull = pllmull >> 18;
      
      if (pllmull != 0x0D)
      {
         pllmull += 2;
      }
      else
      { /* PLL乘法因子 = PLL输入时钟 * 6.5 */
        pllmull = 13 / 2; 
      }
            
      if (pllsource == 0x00)
      {
        /* HSI振荡器时钟除以2选作PLL时钟入口 */
        SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
      }
      else
      {/* PREDIV1选作PLL时钟入口 */
        
        /* 获取PREDIV1时钟源和分频因子 */
        prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
        prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
        
        if (prediv1source == 0)
        { 
          /* HSE振荡器时钟选作PREDIV1时钟入口 */
          SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;          
        }
        else
        {/* PLL2时钟选作PREDIV1时钟入口 */
          
          /* 获取PREDIV2分频因子和PLL2乘法因子 */
          prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1;
          pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2; 
          SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;                         
        }
      }
#endif /* STM32F10X_CL */ 
      break;

    default:
      SystemCoreClock = HSI_VALUE;
      break;
  }
  
  /* 计算HCLK时钟频率 ----------------*/
  /* 获取HCLK预分频器 */
  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
  /* HCLK时钟频率 */
  SystemCoreClock >>= tmp;  
}

/**
  * @brief  配置系统时钟频率、HCLK、PCLK2和PCLK1预分频器。
  * @param  无
  * @retval 无
  */
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#elif defined SYSCLK_FREQ_64MHz
  SetSysClockTo64();
#endif
 
 /* 如果上面没有启用任何定义，则HSI用作系统时钟源
    (复位后的默认值) */ 
}

#ifdef SYSCLK_FREQ_HSE
/**
  * @brief  将系统时钟频率设置为HSE值并配置HCLK、PCLK2 
  *          和PCLK1预分频器。 
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
static void SetSysClockToHSE(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK、HCLK、PCLK2和PCLK1配置 ---------------------------*/    
  /* 启用HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪，如果达到超时则退出 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* 启用预取缓冲器 */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* 闪存2等待状态 */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* 配置PLL ------------------------------------------------------*/
    /* PLL2配置: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1配置: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* 启用PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* 等待PLL2就绪 */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL配置: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /* PLL配置: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* 启用PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择PLL作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLL用作系统时钟源 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* 如果HSE启动失败，应用程序将具有错误的时钟 
         配置。用户可以在此处添加一些代码来处理此错误 */
  }
}
#endif

#ifdef SYSCLK_FREQ_24MHz
/**
  * @brief  将系统时钟频率设置为24MHz并配置HCLK、PCLK2 
  *          和PCLK1预分频器。 
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
static void SetSysClockTo24(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK、HCLK、PCLK2和PCLK1配置 ---------------------------*/    
  /* 启用HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪，如果达到超时则退出 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* 启用预取缓冲器 */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* 闪存2等待状态 */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* 配置PLL ------------------------------------------------------*/
    /* PLL2配置: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1配置: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* 启用PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* 等待PLL2就绪 */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL配置: PLLCLK = PREDIV1 * 3 = 24 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL3); 
#else    
    /* PLL配置: PLLCLK = HSE * 3 = 24 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL3);
#endif /* STM32F10X_CL */

    /* 启用PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择PLL作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLL用作系统时钟源 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* 如果HSE启动失败，应用程序将具有错误的时钟 
         配置。用户可以在此处添加一些代码来处理此错误 */
  }
}
#endif

#ifdef SYSCLK_FREQ_36MHz
/**
  * @brief  将系统时钟频率设置为36MHz并配置HCLK、PCLK2 
  *          和PCLK1预分频器。 
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
static void SetSysClockTo36(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK、HCLK、PCLK2和PCLK1配置 ---------------------------*/    
  /* 启用HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪，如果达到超时则退出 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* 启用预取缓冲器 */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* 闪存2等待状态 */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* 配置PLL ------------------------------------------------------*/
    /* PLL2配置: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1配置: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* 启用PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* 等待PLL2就绪 */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL配置: PLLCLK = PREDIV1 * 4 = 36 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL4); 
#else    
    /* PLL配置: PLLCLK = HSE * 4 = 36 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL4);
#endif /* STM32F10X_CL */

    /* 启用PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择PLL作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLL用作系统时钟源 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* 如果HSE启动失败，应用程序将具有错误的时钟 
         配置。用户可以在此处添加一些代码来处理此错误 */
  }
}
#endif

#ifdef SYSCLK_FREQ_48MHz
/**
  * @brief  将系统时钟频率设置为48MHz并配置HCLK、PCLK2 
  *          和PCLK1预分频器。 
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
static void SetSysClockTo48(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK、HCLK、PCLK2和PCLK1配置 ---------------------------*/    
  /* 启用HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪，如果达到超时则退出 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* 启用预取缓冲器 */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* 闪存2等待状态 */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* 配置PLL ------------------------------------------------------*/
    /* PLL2配置: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1配置: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* 启用PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* 等待PLL2就绪 */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL配置: PLLCLK = PREDIV1 * 6 = 48 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL6); 
#else    
    /* PLL配置: PLLCLK = HSE * 6 = 48 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6);
#endif /* STM32F10X_CL */

    /* 启用PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择PLL作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLL用作系统时钟源 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* 如果HSE启动失败，应用程序将具有错误的时钟 
         配置。用户可以在此处添加一些代码来处理此错误 */
  }
}
#endif

#ifdef SYSCLK_FREQ_56MHz
/**
  * @brief  将系统时钟频率设置为56MHz并配置HCLK、PCLK2 
  *          和PCLK1预分频器。 
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
static void SetSysClockTo56(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK、HCLK、PCLK2和PCLK1配置 ---------------------------*/    
  /* 启用HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪，如果达到超时则退出 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* 启用预取缓冲器 */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* 闪存2等待状态 */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* 配置PLL ------------------------------------------------------*/
    /* PLL2配置: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1配置: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* 启用PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* 等待PLL2就绪 */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL配置: PLLCLK = PREDIV1 * 8 = 64 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL8); 
#else    
    /* PLL配置: PLLCLK = HSE * 8 = 64 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL8);
#endif /* STM32F10X_CL */

    /* 启用PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL就绪 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择PLL作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLL用作系统时钟源 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* 如果HSE启动失败，应用程序将具有错误的时钟 
         配置。用户可以在此处添加一些代码来处理此错误 */
  }
}
#endif

/**
  * @brief  将系统时钟频率设置为64MHz并配置HCLK、PCLK2 
  *          和PCLK1预分频器。 
  * @note   此函数应仅在复位后使用。
  * @param  无
  * @retval 无
  */
static void SetSysClockTo64(void)
{
  /* SYSCLK、HCLK、PCLK2和PCLK1配置 ---------------------------*/    
  /* 启用HSI */    
  RCC->CR |= ((uint32_t)RCC_CR_HSION);
 
  /* 等待HSI就绪 */
  while((RCC->CR & RCC_CR_HSIRDY) == 0)
  {
  }

  /* 启用预取缓冲器 */
  FLASH->ACR |= FLASH_ACR_PRFTBE;

  /* 闪存2等待状态 */
  FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
  FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    


  /* HCLK = SYSCLK */
  RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    
  /* PCLK2 = HCLK */
  RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
  
  /* PCLK1 = HCLK */
  RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
  /* 配置PLL ------------------------------------------------------*/
  /* PLL2配置: PLL2CLK = (HSI / 2) * 8 = 32 MHz */
  /* PREDIV1配置: PREDIV1CLK = PLL2 / 5 = 6.4 MHz */
      
  RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                            RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
  RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV2 | RCC_CFGR2_PLL2MUL8 |
                           RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

  /* 启用PLL2 */
  RCC->CR |= RCC_CR_PLL2ON;
  /* 等待PLL2就绪 */
  while((RCC->CR & RCC_CR_PLL2RDY) == 0)
  {
  }
  
 
  /* PLL配置: PLLCLK = PREDIV1 * 10 = 64 MHz */ 
  RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
  RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                          RCC_CFGR_PLLMULL10); 
#else    
  /* PLL配置: PLLCLK = HSI / 2 * 16 = 64 MHz */
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                      RCC_CFGR_PLLMULL));
  RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL16);
#endif /* STM32F10X_CL */

  /* 启用PLL */
  RCC->CR |= RCC_CR_PLLON;

  /* 等待PLL就绪 */
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
  {
  }
  
  /* 选择PLL作为系统时钟源 */
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

  /* 等待PLL用作系统时钟源 */
  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
  {
  }
}

/**
  * @}
  */

/**
  * @}
  */
  
/**
  * @}
  */    
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
